package redsoxfan.gamejam.base;

import java.util.ArrayList;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;

/**
 * Manage audio
 * @author RedSoxFan
 * @since 20 Apr 14
 * @version 1.0
 */
public class Audio {
	/**
	 * Decoded input stream
	 */
	private AudioInputStream din;
	/**
	 * Clip used to play audio
	 */
	private Clip clip;
	/**
	 * Is this music or a sound effect?
	 */
	private boolean music;
	/**
	 * Mute everything?
	 */
	private static boolean mute = false;
	/**
	 * Mute background music?
	 */
	private static boolean muteBGM = false;
	/**
	 * Mute sound effects?
	 */
	private static boolean muteSFX = false;
	/**
	 * Audio instances
	 */
	private static ArrayList<Audio> instances = new ArrayList<Audio>();
	/**
	 * Audio File
	 * @param ain - Audio input stream
	 * @param music - Music (true) or Sound Effects (false). Music will be looped.
	 */
	protected Audio(AudioInputStream ain, boolean music) {
		try {
			AudioFormat baseFormat = ain.getFormat();
			AudioFormat decodedFormat = new AudioFormat(
					AudioFormat.Encoding.PCM_SIGNED,
					baseFormat.getSampleRate(), 16,
					baseFormat.getChannels(),
					baseFormat.getChannels() * 2,
					baseFormat.getSampleRate(), false);
			din = AudioSystem.getAudioInputStream(decodedFormat, ain);
		    try {
				clip = AudioSystem.getClip();
			} catch (LineUnavailableException e) {
			}
		    this.music = music;
		    instances.add(this);
		} catch (Exception e) {
		}
	}
	/**
	 * Stop all instances and remove them from the instance list
	 */
	public static void clearAll() {
		stopAll();
		instances.clear();
	}
	/**
	 * Is the audio being muted?
	 * @return Whether the audio is mute
	 */
	public static boolean isMute() {
		return mute;
	}
	/**
	 * Is background music muted?
	 * @return Whether the music is muted
	 */
	public static boolean isMuteBackgroundMusic() {
		return muteBGM;
	}
	/**
	 * Are sound effects muted?
	 * @return Whether sound effects are muted
	 */
	public static boolean isMuteSoundEffects() {
		return muteSFX;
	}
	/**
	 * Pause all audio instances
	 */
	public static void pauseAll() {
		for (Audio s:instances)
			s.pause();
	}
	/**
	 * Resume all background music. Sound effects will not be resumed.
	 */
	public static void resumeAll() {
		for (Audio s:instances)
			if (s.isMusic())
				s.resume();
	}
	/**
	 * Set the mute state
	 * @param mute - Master mute state
	 */
	public static void setMute(boolean mute) {
		Audio.mute = mute;
		if (mute)
			pauseAll();
		else
			resumeAll();
	}
	/**
	 * Set mute state for background music
	 * @param muteBGM - Mute state for background music
	 */
	public static void setMuteBackgroundMusic(boolean muteBGM) {
		Audio.muteBGM = muteBGM;
		if (muteBGM) {
			for (Audio s:instances)
				if (s.isMusic())
					s.pause();
		} else {
			for (Audio s:instances)
				if (s.isMusic())
					s.resume();
		}
	}
	/**
	 * Set mute state for sound effects
	 * @param muteSFX - Mute state for sound effects
	 */
	public static void setMuteSoundEffects(boolean muteSFX) {
		Audio.muteSFX = muteSFX;
		if (muteSFX) {
			for (Audio s:instances)
				if (!s.isMusic())
					s.stop();
		}
	}
	/**
	 * Stop all audio instances
	 */
	public static void stopAll() {
		for (Audio s:instances)
			s.stop();
	}
	/**
	 * Is the music (true) or audio (false)?
	 * @return Whether or not this is music
	 */
	public boolean isMusic() {
		return music;
	}
	/**
	 * Is this instance being played?
	 * @return Whether or not this instance is being played
	 */
	public boolean isPlaying() {
		try {
			return clip.isRunning();
		} catch (Exception e){
		}
		return false;
	}
	/**
	 * Pause this instance
	 */
	private void pause() {
		try {
			clip.stop();
		} catch (Exception e){
		}
	}
	/**
	 * Play this instance. If this is sound, it will play once. If music, it will be looped. If the
	 * appropriate entity is muted, no sound will be played
	 */
	public void play() {
		playSound();
		try {
			if (!isMute() && isMusic() && !isMuteBackgroundMusic())
				clip.loop(Clip.LOOP_CONTINUOUSLY);
		} catch (Exception e){
		}
	}
	/**
	 * Play this audio file once
	 */
	private void playSound() {
		try {
			clip.open(din);
			if (!isMute() && (isMusic()&&!isMuteBackgroundMusic() || !isMusic()&&!isMuteSoundEffects()))
				clip.start();
		} catch (Exception e) {
		}
	}
	/**
	 * Resume this instance. Calls play().
	 */
	private void resume() {
		play();
	}
	/**
	 * Stop this instance
	 */
	public void stop() {
		try {
			clip.stop();
			clip.close();
		} catch (Exception e){
		}
	}
}